package com.wangxiaonan.migration.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.smy.cif.domain.CstCustInfo;
import com.smy.cif.domain.CstUser;
import com.smy.cif.service.CustService;
import com.wangxiaonan.migration.domain.*;
import com.wangxiaonan.migration.dto.AppInfoQueryParms;
import com.wangxiaonan.migration.dto.GlobalProgressList;
import com.wangxiaonan.migration.dto.Progress;
import com.wangxiaonan.migration.service.AppInformationService;
import com.wangxiaonan.migration.service.ESService;
import com.wangxiaonan.migration.service.SearchAppInfoService;
import com.wangxiaonan.migration.utils.CommonUtils;
import com.wangxiaonan.migration.utils.EmojiUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @Author: wangxiaonan
 * @Date: 2018/7/18
 **/
@Service
@Transactional
public class SearchAppInfoServiceImpl implements SearchAppInfoService {
    private static final Logger logger = LoggerFactory.getLogger(SearchAppInfoServiceImpl.class);
    @Autowired
    private ESService esService;
    @Autowired
    private AppInformationService appInformationService;

    @Reference(check = false)
    private com.smy.cif.service.UserService userService;
    @Reference(check = false)
    private CustService custService;

    @Override
    public <T extends Base> Page<T> searchAppInfo(Class<T> clazz, SearchParams searchParams) {
        Page<T> collectAppInfos = esService.searchInfo(clazz, initParams(searchParams));
        return collectAppInfos;
    }

    public AppInfoQueryParms initParams(SearchParams searchParams) {
        String indices = searchParams.getIndices();
        String contents = searchParams.getContents();
        Pageable pageable = searchParams.getPageable();

        AppInfoQueryParms appInfoQueryParms = new AppInfoQueryParms();
        String[] indice = StringUtils.split(indices, ',');
        List<String> indexList = new ArrayList<>();
        for (String i : indice) {
            indexList.add(i);
        }
        appInfoQueryParms.setIndices(indexList);

        appInfoQueryParms.setPage(pageable.getPageNumber());
        appInfoQueryParms.setSize(pageable.getPageSize());

        Map<String, String> content = new HashMap<>();
        String[] contentArray = StringUtils.split(contents, ';');
        for (String s : contentArray) {
            String[] k_v = StringUtils.split(s, '@');
            if (k_v.length < 2) {
                continue;
            }
            content.put(k_v[0], k_v[1]);
        }
        appInfoQueryParms.setQueryContent(content);
        appInfoQueryParms.setScroll(searchParams.getScroll());
        appInfoQueryParms.setScrollId(searchParams.getScrollId());
        return appInfoQueryParms;
    }

    @Override
    @Deprecated
    public String migrationAppInfo(SearchParams searchParams) {
        JSONObject rs = new JSONObject();
        int insertTotal = 0;
        int badRecord = 0;

        Page<CollectAppInfo> collectAppInfos = esService.searchInfo(CollectAppInfo.class, initParams(searchParams));
        if (collectAppInfos == null) {
            throw new NullPointerException("[SearchAppInfoServiceImpl - migrationAppInfo] 查询为空");
        }

        if (collectAppInfos == null) {
            rs.put("result", "null");
            rs.put("message", "未查询到结果");
            return rs.toJSONString();
        }

        while (collectAppInfos.getNumber() < collectAppInfos.getTotalPages()) {

            for (CollectAppInfo info : collectAppInfos.getContent()) {
                String body = info.getBody();
                JSONObject jsonBody;
                try {
                    String paresbody = body.substring(body.indexOf(':') + 1, body.length());
                    jsonBody = JSONObject.parseObject(paresbody);
                } catch (JSONException e) {
                    badRecord++;
//                    logger.error("[SearchAppInfoServiceImpl ==> migrationAppInfo] BadRecord ==> paresbody: {}", body);
                    continue;
                }
                AppInformation _appInfo = new AppInformation();
                try {
                    JSONArray appInfoArray = jsonBody.getJSONArray("appInfoList");

                    List<String> appNameList = new ArrayList<>();
                    if (appInfoArray == null) {
                        badRecord++;
//                        logger.error("[SearchAppInfoServiceImpl ==> migrationAppInfo] BadRecord ==> appInfoList 为空 null ===> json: {}", jsonBody);
                        continue;
                    }
                    for (JSONObject appInfo : appInfoArray.toJavaList(JSONObject.class)) {
                        appNameList.add(appInfo.getString("appName"));
                    }
                    JSONObject environmentInfo = jsonBody.getJSONObject("environmentInfo");
                    String deviceUniqueId = environmentInfo.getString("deviceUniqueId");


                    _appInfo.setAppNameList(StringUtils.join(appNameList, ','));
                    _appInfo.setDeviceUniqueId(deviceUniqueId);
                } catch (Exception e) {
                    badRecord++;
//                    logger.error("[SearchAppInfoServiceImpl ==> migrationAppInfo] BadRecord ==>  {}", e.getMessage());
                    continue;
                }

                appInformationService.insert(_appInfo);
                insertTotal++;
            }

            if (collectAppInfos.hasNext()) {
                searchParams.setPageable(searchParams.getPageable().next());
                collectAppInfos = esService.searchInfo(CollectAppInfo.class, initParams(searchParams));
            } else {
                break;
            }

        }

        rs.put("insertTotal", insertTotal);
        rs.put("badRecord", badRecord);
        rs.put("totalElements", collectAppInfos.getTotalElements());
        rs.put("indices", searchParams.getIndices());
        rs.put("contents", searchParams.getContents());
        return rs.toJSONString();
    }

    @Override
    public <T extends Base> String migrationAppInfoByScroll(Class<T> clazz, SearchParams searchParams) {
        JSONObject rs = new JSONObject();
        int insertTotal = 0;
        int badRecord = 0;
        Map<String, Progress> progressMap = GlobalProgressList.getInstance();
        Progress progress = progressMap.get(GlobalProgressList.PROGRESS_NAME_APP_INFO);
        if (progress == null) {
            progress = new Progress();
        }
        progress.init(searchParams.getIndices());
        progressMap.put(GlobalProgressList.PROGRESS_NAME_APP_INFO, progress);

        // 第一次没有scroll_id，所以不用设置
        QueryResult<T> queryResult = esService.searchInfoByScroll(clazz, initParams(searchParams));
        if (queryResult == null) {
            throw new NullPointerException("[SearchAppInfoServiceImpl - migrationAppInfo] 查询为空");
        }

        Page<T> collectAppInfos = queryResult.getPage();
        rs.put("totalElements", collectAppInfos.getTotalElements());

        if (collectAppInfos == null) {
            rs.put("result", "null");
            rs.put("message", "未查询到结果");
            return rs.toJSONString();
        }

        long totalElements = collectAppInfos.getTotalElements();
        progressMap.get(GlobalProgressList.PROGRESS_NAME_APP_INFO).setTotal((int) totalElements);

        while (collectAppInfos.getContent().size() > 0) {
            for (T info : collectAppInfos.getContent()) {
                String body = info.getBody();
                JSONObject jsonBody;
                try {
//                    String paresbody = formateFrontInfo(body);
                    String paresbody = formateBus(body);
                    jsonBody = JSONObject.parseObject(paresbody);
                } catch (Exception e) {
                    badRecord++;
                    logger.error("[SearchAppInfoServiceImpl ==> migrationAppInfo] BadRecord ===> paresbody: {}", body);
                    continue;
                }
                AppInformation _appInfo = new AppInformation();
                try {
                    JSONArray appInfoArray = jsonBody.getJSONArray("appInfoList");

                    // appNameList
                    List<String> appNameList = new ArrayList<>();
                    if (appInfoArray == null) {
                        badRecord++;
                        logger.error("[SearchAppInfoServiceImpl ==> migrationAppInfo] BadRecord ==> appInfoList 为空 null ===> json: {}", jsonBody);
                        continue;
                    }
                    for (JSONObject appInfo : appInfoArray.toJavaList(JSONObject.class)) {
                        appNameList.add(appInfo.getString("appName"));
                    }

                    // deviceUniqueId
                    JSONObject session = jsonBody.getJSONObject("session");
                    String deviceUniqueId = session.getString("deviceKey");

                    // userID --> cif: customerName, customerMobileNo, customerIdNo
                    String userId = session.getString("userID");
                    try {
                        CstUser cstUser = userService.checkUser(userId);
                        if (cstUser != null && StringUtils.isNotBlank(cstUser.getLoginName())) {
                            _appInfo.setMobile(cstUser.getLoginName());
                            CstCustInfo cstCustInfo = custService.queryCstUserCustInfoByMobileNo(cstUser.getLoginName());
                            _appInfo.setCustName(cstCustInfo.getCustName());
                            _appInfo.setIdNo(cstCustInfo.getIdNo());
                        } else {
                            // 无记录继续保存
                            // continue;
                        }
                    } catch (Exception e) {
                        logger.error("[SearchAppInfoServiceImpl ==> cif] BadRemoteRequest loginName:{} IDNo:{}", _appInfo.getMobile(), _appInfo.getIdNo());
                    }

                    // createDate, createTime, updateDate, updateTime
                    Date date = CommonUtils.str2Date(info.getDatetime());
                    int dateInt = CommonUtils.dateInt(date);
                    String timeStr = CommonUtils.timeString(date);

                    // appNameList
                    _appInfo.setAppNameList(subAppNameList(StringUtils.join(appNameList, ','), 4000));
                    _appInfo.setDeviceUniqueId(deviceUniqueId);
                    _appInfo.setCreateDate(dateInt);
                    _appInfo.setCreateTime(timeStr);
                    _appInfo.setUpdateDate(dateInt);
                    _appInfo.setUpdateTime(timeStr);
                } catch (Exception e) {
                    badRecord++;
                    logger.error("[SearchAppInfoServiceImpl ==> migrationAppInfo] BadRecord ==>  {}", e.getMessage());
                    continue;
                }

                appInformationService.insert(_appInfo);
                insertTotal++;
                progressMap.get(GlobalProgressList.PROGRESS_NAME_APP_INFO).setCurNum(insertTotal + badRecord);
            }

            // 次数大于1次，要使用上次返回的scroll_id作为参数查询
            // 不过始终用同一个也没有出现问题，可能和scroll（设置游标窗口失效时间）值有关，但不确定
            searchParams.setScrollId(queryResult.getScrollId());
            queryResult = esService.searchInfoByScroll(clazz, initParams(searchParams));
            collectAppInfos = queryResult.getPage();
            logger.info("[total/totalElements/insertTotal/badRecord] ==========>> {}/{}/{}/{}", insertTotal + badRecord, totalElements, insertTotal, badRecord);
        }

        progressMap.get(GlobalProgressList.PROGRESS_NAME_APP_INFO).setCurNum(insertTotal + badRecord);

        rs.put("insertTotal", insertTotal);
        rs.put("badRecord", badRecord);
        rs.put("totalElements", totalElements);
        rs.put("indices", searchParams.getIndices());
        rs.put("contents", searchParams.getContents());
        rs.put("scrollId", searchParams.getContents());
        rs.put("scroll", searchParams.getContents());
        return rs.toJSONString();
    }

    private String subAppNameList(String appNameList, int length) {
        String appName = appNameList;
        if (appName.length() > length) {
            appName = StringUtils.abbreviate(appName, length + 3);
            appName = StringUtils.substring(appName, 0, appName.lastIndexOf(','));
            logger.info("[subAppNameList] <<<<<<<< appNames --> length = {} >>>>>>>>>", appNameList.length());
        }
        // 过滤Emoj表情字符
        return EmojiUtil.emojiFilter(appName, "");
    }

    private String formateFrontInfo(String body) {
        String _str = body;
        return _str.substring(_str.indexOf(':') + 1, _str.length());
    }

    private String formateBus(String body) {
        String _str = body;
        _str = StringUtils.replace(_str, "=>", ":");
        _str = StringUtils.replace(_str, "#<", "\"");
        _str = StringUtils.replace(_str, ")>", ")\"");
        JSONObject json = JSONObject.parseObject(_str);
        JSONObject strJSON = json.getJSONObject("BNHUserController.collectAppInfo.arg1");
        return strJSON.toJSONString();
    }

}
